Laying the groundwork for interactive reporting & dashboards…
- ggplot2 and gridExtra
library(ggplot2)
library(gridExtra)
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
data(anscombe)
sapply(1:4, function(x) cor(anscombe[, x], anscombe[, x+4]))
[1] 0.8164205 0.8162365 0.8162867 0.8165214
sapply(5:8, function(x) var(anscombe[, x]))
[1] 4.127269 4.127629 4.122620 4.123249
lm(y1 ~ x1, data = anscombe)
Call:
lm(formula = y1 ~ x1, data = anscombe)
Coefficients:
(Intercept) x1
3.0001 0.5001
p1 <- ggplot(anscombe) + geom_point(aes(x1, y1), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 1")
p2 <- ggplot(anscombe) + geom_point(aes(x2, y2), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 2")
p3 <- ggplot(anscombe) + geom_point(aes(x3, y3), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 3")
p4 <- ggplot(anscombe) + geom_point(aes(x4, y4), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 4")
grid.arrange(p1, p2, p3, p4, top = "Anscombe's Quartet")

library(ggplot2)
p <- ggplot(data = diamonds, aes(x = cut, fill = clarity)) +
geom_bar(position = "dodge")
p

2.B Plotly
http://www.htmlwidgets.org/showcase_plotly.html
https://plot.ly/r/dashboard/
https://plot.ly/r/shiny-tutorial/
library(plotly)
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
ggplotly(p)
d <- diamonds[sample(nrow(diamonds), 500), ]
plot_ly(d, x = d$carat, y = d$price,
text = paste("Clarity: ", d$clarity),
mode = "markers", color = d$carat, size = d$carat)
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plot.ly/r/reference/#scatter
`arrange_()` is deprecated as of dplyr 0.7.0.
Please use `arrange()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.`line.width` does not currently support multiple values.No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plot.ly/r/reference/#scatter
`line.width` does not currently support multiple values.
- HTML Widgets
http://www.htmlwidgets.org
2.A Dygraphs
http://www.htmlwidgets.org/showcase_dygraphs.html
Basic plot example:
## standard graphics device
library(stats)
plot(nhtemp, main = "nhtemp data", ylab = "Mean annual temp. in F)")

## using dygraphs
library(dygraphs)
fig <- dygraph(nhtemp, main = "New Haven Temperatures")
fig <- dyAxis(fig, "y", label = "Temp (F)", valueRange = c(40, 60))
fig <- dyOptions(fig, axisLineWidth = 1.5, fillGraph = TRUE, drawGrid = FALSE)
fig
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dySeries("V1", label = "Temperature (F)") %>%
dyLegend(show = "always", hideOnMouseOut = FALSE)
NA
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector()
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector(dateWindow = c("1920-01-01", "1960-01-01"))
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector(height = 20, strokeColor = "")
#Shaded Regions
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyShading(from = "1920-1-1", to = "1930-1-1") %>%
dyShading(from = "1940-1-1", to = "1950-1-1")
dygraph(nhtemp, main = "New Haven Temperatures") %>%
dySeries(label = "Temp (F)", color = "black") %>%
dyShading(from = "1920-1-1", to = "1930-1-1", color = "#FFE6E6") %>%
dyShading(from = "1940-1-1", to = "1950-1-1", color = "#CCEBD6")
library(quantmod)
library(dygraphs)
prices <- round(getSymbols("MSFT", from = "2014-06-01", auto.assign = FALSE), 2)
ret = ROC(prices[, 4])
mn = mean(ret, na.rm = TRUE)
std = sd(ret, na.rm = TRUE)
dygraph(ret, main = "Microsoft Share Price") %>%
dySeries("MSFT.Close", label = "MSFT") %>%
dyShading(from = mn - std, to = mn + std, axis = "y")
NA
NA
prices <- round(getSymbols("MSFT", from = "2014-06-01", auto.assign = FALSE), 2)
dygraph(prices[, 4], main = "Microsoft Share Price") %>%
dySeries("MSFT.Close", label = "MSFT") %>%
dyLimit(as.numeric(prices[1, 4]), color = "red")
getSymbols(c("MSFT", "HPQ"), from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT" "HPQ"
stocks <- cbind(MSFT[,2:4], HPQ[,2:4])
dygraph(stocks, main = "Microsoft and HP Share Prices") %>%
dySeries(c("MSFT.Low", "MSFT.Close", "MSFT.High"), label = "MSFT") %>%
dySeries(c("HPQ.Low", "HPQ.Close", "HPQ.High"), label = "HPQ")
2.C rbokeh
http://www.htmlwidgets.org/showcase_rbokeh.html
library(rbokeh)
Registered S3 method overwritten by 'pryr':
method from
print.bytes Rcpp
figure() %>%
ly_points(Sepal.Length, Sepal.Width, data = iris,
color = Species, glyph = Species,
hover = list(Sepal.Length, Sepal.Width))
figure(width = NULL, height = NULL, legend_location = "top_left") %>%
ly_quantile(Sepal.Length, group = Species, data = iris)
figure(width = NULL, height = NULL) %>%
ly_points(Sepal.Length, Sepal.Width, data = iris,
color = Petal.Width)
tools <- c("pan", "wheel_zoom", "box_zoom", "box_select", "reset")
nms <- expand.grid(names(iris)[1:4], rev(names(iris)[1:4]), stringsAsFactors = FALSE)
splom_list <- vector("list", 16)
for(ii in seq_len(nrow(nms))) {
splom_list[[ii]] <- figure(width = 200, height = 200, tools = tools,
xlab = nms$Var1[ii], ylab = nms$Var2[ii]) %>%
ly_points(nms$Var1[ii], nms$Var2[ii], data = iris,
color = Species, size = 5, legend = FALSE)
}
grid_plot(splom_list, ncol = 4, same_axes = TRUE, link_data = TRUE)
2.4 DT
http://www.htmlwidgets.org/showcase_datatables.html
library(DT)
datatable(iris, options = list(pageLength = 5))
- Crosstalk
http://rstudio.github.io/crosstalk/index.html
http://rstudio.github.io/crosstalk/shiny.html
Examples:
LS0tCnRpdGxlOiAiSW50ZXJhY3RpdmUgUmVwb3J0aW5nIERhc2hib2FyZHMgaW4gU2hpbnkiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KCkxheWluZyB0aGUgZ3JvdW5kd29yayBmb3IgaW50ZXJhY3RpdmUgcmVwb3J0aW5nICYgZGFzaGJvYXJkcy4uLgoKMS4gZ2dwbG90MiBhbmQgZ3JpZEV4dHJhCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKCmRhdGEoYW5zY29tYmUpCgpzYXBwbHkoMTo0LCBmdW5jdGlvbih4KSBjb3IoYW5zY29tYmVbLCB4XSwgYW5zY29tYmVbLCB4KzRdKSkKc2FwcGx5KDU6OCwgZnVuY3Rpb24oeCkgdmFyKGFuc2NvbWJlWywgeF0pKQpsbSh5MSB+IHgxLCBkYXRhID0gYW5zY29tYmUpCgpwMSA8LSBnZ3Bsb3QoYW5zY29tYmUpICsgZ2VvbV9wb2ludChhZXMoeDEsIHkxKSwgY29sb3IgPSAiZGFya29yYW5nZSIsIHNpemUgPSAzKSArIHRoZW1lX2J3KCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwLCAyKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEyLCAyKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzLCBzbG9wZSA9IDAuNSwgY29sb3IgPSAiY29ybmZsb3dlcmJsdWUiKSArIGV4cGFuZF9saW1pdHMoeCA9IDAsIHkgPSAwKSArIGxhYnModGl0bGUgPSAiZGF0YXNldCAxIikKcDIgPC0gZ2dwbG90KGFuc2NvbWJlKSArIGdlb21fcG9pbnQoYWVzKHgyLCB5MiksIGNvbG9yID0gImRhcmtvcmFuZ2UiLCBzaXplID0gMykgKyB0aGVtZV9idygpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyMCwgMikpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMiwgMikpICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMywgc2xvcGUgPSAwLjUsIGNvbG9yID0gImNvcm5mbG93ZXJibHVlIikgKyBleHBhbmRfbGltaXRzKHggPSAwLCB5ID0gMCkgKyBsYWJzKHRpdGxlID0gImRhdGFzZXQgMiIpCnAzIDwtIGdncGxvdChhbnNjb21iZSkgKyBnZW9tX3BvaW50KGFlcyh4MywgeTMpLCBjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZSA9IDMpICsgdGhlbWVfYncoKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMjAsIDIpKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTIsIDIpKSArIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDMsIHNsb3BlID0gMC41LCBjb2xvciA9ICJjb3JuZmxvd2VyYmx1ZSIpICsgZXhwYW5kX2xpbWl0cyh4ID0gMCwgeSA9IDApICsgbGFicyh0aXRsZSA9ICJkYXRhc2V0IDMiKQpwNCA8LSBnZ3Bsb3QoYW5zY29tYmUpICsgZ2VvbV9wb2ludChhZXMoeDQsIHk0KSwgY29sb3IgPSAiZGFya29yYW5nZSIsIHNpemUgPSAzKSArIHRoZW1lX2J3KCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwLCAyKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEyLCAyKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzLCBzbG9wZSA9IDAuNSwgY29sb3IgPSAiY29ybmZsb3dlcmJsdWUiKSArIGV4cGFuZF9saW1pdHMoeCA9IDAsIHkgPSAwKSArIGxhYnModGl0bGUgPSAiZGF0YXNldCA0IikKCmdyaWQuYXJyYW5nZShwMSwgcDIsIHAzLCBwNCwgdG9wID0gIkFuc2NvbWJlJ3MgUXVhcnRldCIpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpwIDwtIGdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gY3V0LCBmaWxsID0gY2xhcml0eSkpICsKICAgICAgICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKQpwCmBgYAoKCjIuQiBQbG90bHkKCmh0dHA6Ly93d3cuaHRtbHdpZGdldHMub3JnL3Nob3djYXNlX3Bsb3RseS5odG1sCgpodHRwczovL3Bsb3QubHkvci9kYXNoYm9hcmQvCgpodHRwczovL3Bsb3QubHkvci9zaGlueS10dXRvcmlhbC8KCgoKCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKZ2dwbG90bHkocCkKYGBgCgpgYGB7cn0KZCA8LSBkaWFtb25kc1tzYW1wbGUobnJvdyhkaWFtb25kcyksIDUwMCksIF0KcGxvdF9seShkLCB4ID0gZCRjYXJhdCwgeSA9IGQkcHJpY2UsIAogICAgICAgIHRleHQgPSBwYXN0ZSgiQ2xhcml0eTogIiwgZCRjbGFyaXR5KSwKICAgICAgICBtb2RlID0gIm1hcmtlcnMiLCBjb2xvciA9IGQkY2FyYXQsIHNpemUgPSBkJGNhcmF0KQoKYGBgCgoKMi4gSFRNTCBXaWRnZXRzCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZwoKMi5BIER5Z3JhcGhzCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9keWdyYXBocy5odG1sCgpCYXNpYyBwbG90IGV4YW1wbGU6CgpgYGB7cn0KIyMgc3RhbmRhcmQgZ3JhcGhpY3MgZGV2aWNlCmxpYnJhcnkoc3RhdHMpCnBsb3Qobmh0ZW1wLCBtYWluID0gIm5odGVtcCBkYXRhIiwgeWxhYiA9ICJNZWFuIGFubnVhbCB0ZW1wLiBpbiBGKSIpCgpgYGAKCgpgYGB7cn0KIyMgdXNpbmcgZHlncmFwaHMKbGlicmFyeShkeWdyYXBocykKZmlnIDwtIGR5Z3JhcGgobmh0ZW1wLCBtYWluID0gIk5ldyBIYXZlbiBUZW1wZXJhdHVyZXMiKQpmaWcgPC0gZHlBeGlzKGZpZywgInkiLCBsYWJlbCA9ICJUZW1wIChGKSIsIHZhbHVlUmFuZ2UgPSBjKDQwLCA2MCkpCmZpZyA8LSBkeU9wdGlvbnMoZmlnLCBheGlzTGluZVdpZHRoID0gMS41LCBmaWxsR3JhcGggPSBUUlVFLCBkcmF3R3JpZCA9IEZBTFNFKQpmaWcKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVNlcmllcygiVjEiLCBsYWJlbCA9ICJUZW1wZXJhdHVyZSAoRikiKSAlPiUKICBkeUxlZ2VuZChzaG93ID0gImFsd2F5cyIsIGhpZGVPbk1vdXNlT3V0ID0gRkFMU0UpCgpgYGAKCmBgYHtyfQpkeWdyYXBoKG5odGVtcCwgbWFpbiA9ICJOZXcgSGF2ZW4gVGVtcGVyYXR1cmVzIikgJT4lIAogIGR5UmFuZ2VTZWxlY3RvcigpCmBgYAoKYGBge3J9CmR5Z3JhcGgobmh0ZW1wLCBtYWluID0gIk5ldyBIYXZlbiBUZW1wZXJhdHVyZXMiKSAlPiUgCiAgZHlSYW5nZVNlbGVjdG9yKGRhdGVXaW5kb3cgPSBjKCIxOTIwLTAxLTAxIiwgIjE5NjAtMDEtMDEiKSkKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoaGVpZ2h0ID0gMjAsIHN0cm9rZUNvbG9yID0gIiIpCmBgYAoKYGBge3J9CiNTaGFkZWQgUmVnaW9ucwpkeWdyYXBoKG5odGVtcCwgbWFpbiA9ICJOZXcgSGF2ZW4gVGVtcGVyYXR1cmVzIikgJT4lIAogIGR5U2hhZGluZyhmcm9tID0gIjE5MjAtMS0xIiwgdG8gPSAiMTkzMC0xLTEiKSAlPiUKICBkeVNoYWRpbmcoZnJvbSA9ICIxOTQwLTEtMSIsIHRvID0gIjE5NTAtMS0xIikKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVNlcmllcyhsYWJlbCA9ICJUZW1wIChGKSIsIGNvbG9yID0gImJsYWNrIikgJT4lCiAgZHlTaGFkaW5nKGZyb20gPSAiMTkyMC0xLTEiLCB0byA9ICIxOTMwLTEtMSIsIGNvbG9yID0gIiNGRkU2RTYiKSAlPiUKICBkeVNoYWRpbmcoZnJvbSA9ICIxOTQwLTEtMSIsIHRvID0gIjE5NTAtMS0xIiwgY29sb3IgPSAiI0NDRUJENiIpCmBgYAoKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkoZHlncmFwaHMpCgpwcmljZXMgPC0gcm91bmQoZ2V0U3ltYm9scygiTVNGVCIsIGZyb20gPSAiMjAxNC0wNi0wMSIsIGF1dG8uYXNzaWduID0gRkFMU0UpLCAyKQoKcmV0ID0gUk9DKHByaWNlc1ssIDRdKQptbiA9IG1lYW4ocmV0LCBuYS5ybSA9IFRSVUUpCnN0ZCA9IHNkKHJldCwgbmEucm0gPSBUUlVFKQpkeWdyYXBoKHJldCwgbWFpbiA9ICJNaWNyb3NvZnQgU2hhcmUgUHJpY2UiKSAlPiUgCiAgZHlTZXJpZXMoIk1TRlQuQ2xvc2UiLCBsYWJlbCA9ICJNU0ZUIikgJT4lCiAgZHlTaGFkaW5nKGZyb20gPSBtbiAtIHN0ZCwgdG8gPSBtbiArIHN0ZCwgYXhpcyA9ICJ5IikKCgpgYGAKCmBgYHtyfQpwcmljZXMgPC0gcm91bmQoZ2V0U3ltYm9scygiTVNGVCIsIGZyb20gPSAiMjAxNC0wNi0wMSIsIGF1dG8uYXNzaWduID0gRkFMU0UpLCAyKQpkeWdyYXBoKHByaWNlc1ssIDRdLCBtYWluID0gIk1pY3Jvc29mdCBTaGFyZSBQcmljZSIpICU+JSAKICBkeVNlcmllcygiTVNGVC5DbG9zZSIsIGxhYmVsID0gIk1TRlQiKSAlPiUKICBkeUxpbWl0KGFzLm51bWVyaWMocHJpY2VzWzEsIDRdKSwgY29sb3IgPSAicmVkIikKYGBgCgpgYGB7cn0KZ2V0U3ltYm9scyhjKCJNU0ZUIiwgIkhQUSIpLCBmcm9tID0gIjIwMTQtMDYtMDEiLCBhdXRvLmFzc2lnbj1UUlVFKQoKc3RvY2tzIDwtIGNiaW5kKE1TRlRbLDI6NF0sIEhQUVssMjo0XSkKZHlncmFwaChzdG9ja3MsIG1haW4gPSAiTWljcm9zb2Z0IGFuZCBIUCBTaGFyZSBQcmljZXMiKSAlPiUgCiAgZHlTZXJpZXMoYygiTVNGVC5Mb3ciLCAiTVNGVC5DbG9zZSIsICJNU0ZULkhpZ2giKSwgbGFiZWwgPSAiTVNGVCIpICU+JQogIGR5U2VyaWVzKGMoIkhQUS5Mb3ciLCAiSFBRLkNsb3NlIiwgIkhQUS5IaWdoIiksIGxhYmVsID0gIkhQUSIpCmBgYAoKCgoyLkMgcmJva2VoCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9yYm9rZWguaHRtbAoKYGBge3J9CgpsaWJyYXJ5KHJib2tlaCkKZmlndXJlKCkgJT4lCiAgbHlfcG9pbnRzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgsIGRhdGEgPSBpcmlzLAogICAgY29sb3IgPSBTcGVjaWVzLCBnbHlwaCA9IFNwZWNpZXMsCiAgICBob3ZlciA9IGxpc3QoU2VwYWwuTGVuZ3RoLCBTZXBhbC5XaWR0aCkpCmBgYAoKYGBge3J9CmZpZ3VyZSh3aWR0aCA9IE5VTEwsIGhlaWdodCA9IE5VTEwsIGxlZ2VuZF9sb2NhdGlvbiA9ICJ0b3BfbGVmdCIpICU+JQogIGx5X3F1YW50aWxlKFNlcGFsLkxlbmd0aCwgZ3JvdXAgPSBTcGVjaWVzLCBkYXRhID0gaXJpcykKYGBgCgoKYGBge3J9CmZpZ3VyZSh3aWR0aCA9IE5VTEwsIGhlaWdodCA9IE5VTEwpICU+JQogIGx5X3BvaW50cyhTZXBhbC5MZW5ndGgsIFNlcGFsLldpZHRoLCBkYXRhID0gaXJpcywKICAgIGNvbG9yID0gUGV0YWwuV2lkdGgpCmBgYAoKYGBge3J9CnRvb2xzIDwtIGMoInBhbiIsICJ3aGVlbF96b29tIiwgImJveF96b29tIiwgImJveF9zZWxlY3QiLCAicmVzZXQiKQpubXMgPC0gZXhwYW5kLmdyaWQobmFtZXMoaXJpcylbMTo0XSwgcmV2KG5hbWVzKGlyaXMpWzE6NF0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCnNwbG9tX2xpc3QgPC0gdmVjdG9yKCJsaXN0IiwgMTYpCmZvcihpaSBpbiBzZXFfbGVuKG5yb3cobm1zKSkpIHsKICBzcGxvbV9saXN0W1tpaV1dIDwtIGZpZ3VyZSh3aWR0aCA9IDIwMCwgaGVpZ2h0ID0gMjAwLCB0b29scyA9IHRvb2xzLAogICAgeGxhYiA9IG5tcyRWYXIxW2lpXSwgeWxhYiA9IG5tcyRWYXIyW2lpXSkgJT4lCiAgICBseV9wb2ludHMobm1zJFZhcjFbaWldLCBubXMkVmFyMltpaV0sIGRhdGEgPSBpcmlzLAogICAgICBjb2xvciA9IFNwZWNpZXMsIHNpemUgPSA1LCBsZWdlbmQgPSBGQUxTRSkKfQpncmlkX3Bsb3Qoc3Bsb21fbGlzdCwgbmNvbCA9IDQsIHNhbWVfYXhlcyA9IFRSVUUsIGxpbmtfZGF0YSA9IFRSVUUpCmBgYAoKMi40IERUCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9kYXRhdGFibGVzLmh0bWwKCmBgYHtyfQpsaWJyYXJ5KERUKQpkYXRhdGFibGUoaXJpcywgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDUpKQpgYGAKCjYuIENyb3NzdGFsawoKaHR0cDovL3JzdHVkaW8uZ2l0aHViLmlvL2Nyb3NzdGFsay9pbmRleC5odG1sCgpodHRwOi8vcnN0dWRpby5naXRodWIuaW8vY3Jvc3N0YWxrL3NoaW55Lmh0bWwKCkV4YW1wbGVzOgo=